<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8"/>
  <title>Hello React!</title>
  <!--<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>-->
  <!--<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>-->
  <!--<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>-->
</head>
<body>

  <div id="example"></div>
  <script>

    // const element = <h1>Hello, world!</h1>;
    // ReactDOM.render(
    //   element,
    //   document.getElementById('example')
    // );
    let config = {
      "iceServers": [
        { "urls": ["stun:b.7mo.org:3478"] }
      ],
      "iceTransportPolicy": "all",
      "iceCandidatePoolSize": "0"
    };

    let pc = new RTCPeerConnection(config);
    /*

      // ice事件候选地址消息
      pc.onicecandidate = (iceEvent) => {
        const elapsed = ((window.performance.now() - begin) / 1000).toFixed(3);
        // console.log('elapsed', elapsed);
        window.iceEvent = iceEvent;
        console.log('elapsed %s iceEvent %o', elapsed, iceEvent);
        if (iceEvent.candidate) {
          if (iceEvent.candidate.candidate === '') {
            return;
          }
          let {candidate} = iceEvent;
          console.log('iceEvent.candidate', candidate);
          candidates.push(candidate);
          window.candidate = candidate;
          let candidateObj = SDPUtils.parseCandidate(candidate.candidate);
          let {component, type, foundation, protocol, address, port} = candidateObj;
          console.log(candidate, component, type, foundation, protocol, address, port)
        } else if (!('onicegatheringstatechange' in RTCPeerConnection.prototype)) {
          // should not be done if its done in the icegatheringstatechange callback.
          console.log('should not be done if its done in the icegatheringstatechange callback.');
          pc.close();
          pc = null;
        }
      };
    */
    /*
      //ice候选地址错误事件
      pc.onicecandidateerror = (iceErrorEvent) => {
        window.iceErrorEvent = iceErrorEvent;
        console.log('iceErrorEvent', iceErrorEvent);
      };*/
    /*
      //ice连接状态改变事件
      pc.oniceconnectionstatechange = (iceConnectionStateChangeEvent) => {
        window.iceConnectionStateChangeEvent = iceConnectionStateChangeEvent;
        console.log('iceConnectionStateChangeEvent', iceConnectionStateChangeEvent);
      };*/
    /*

      //ice收集信息状态改变事件
      pc.onicegatheringstatechange = (onIceGatheringStateChangeEvent) => {
        window.onIceGatheringStateChangeEvent = onIceGatheringStateChangeEvent;
        console.log('onIceGatheringStateChangeEvent', onIceGatheringStateChangeEvent);
        console.log('iceGatheringState', pc.iceGatheringState)
      };
    */


    const offerOptions = { offerToReceiveAudio: 1 };
    let begin;
    let candidates;
    let NativeRTCIceCandidate = window.RTCIceCandidate;

    // let SDPUtils = {};

    // Generate a session ID for SDP.
    // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1
    // recommends using a cryptographically random +ve 64-bit value
    // but right now this should be acceptable and within the right range
    // SDPUtils.generateSessionId = function () {
    //   return Math.random().toString().substr(2, 21);
    // };

    // Parses an ICE candidate line. Sample input:
    // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
    // rport 55996"
    // SDPUtils.parseCandidate = function (line) {
    //   let parts;
    //   // Parse both variants.
    //   if (line.indexOf('a=candidate:') === 0) {
    //     parts = line.substring(12).split(' ');
    //   } else {
    //     parts = line.substring(10).split(' ');
    //   }
    //
    //   let candidate = {
    //     foundation: parts[0],
    //     component: parseInt(parts[1], 10),
    //     protocol: parts[2].toLowerCase(),
    //     priority: parseInt(parts[3], 10),
    //     ip: parts[4],
    //     address: parts[4], // address is an alias for ip.
    //     port: parseInt(parts[5], 10),
    //     // skip parts[6] == 'typ'
    //     type: parts[7]
    //   };
    //
    //   for (let i = 8; i < parts.length; i += 2) {
    //     switch (parts[i]) {
    //       case 'raddr':
    //         candidate.relatedAddress = parts[i + 1];
    //         break;
    //       case 'rport':
    //         candidate.relatedPort = parseInt(parts[i + 1], 10);
    //         break;
    //       case 'tcptype':
    //         candidate.tcpType = parts[i + 1];
    //         break;
    //       case 'ufrag':
    //         candidate.ufrag = parts[i + 1]; // for backward compability.
    //         candidate.usernameFragment = parts[i + 1];
    //         break;
    //       default: // extension handling, in particular ufrag
    //         candidate[parts[i]] = parts[i + 1];
    //         break;
    //     }
    //   }
    //   return candidate;
    // };

    // let _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
    //   return typeof obj;
    // } : function (obj) {
    //   return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    // };

    /*window.RTCIceCandidate = function RTCIceCandidate(args) {
      // Remove the a= which shouldn't be part of the candidate string.
      if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) {
        args = JSON.parse(JSON.stringify(args));
        args.candidate = args.candidate.substr(2);
      }

      if (args.candidate && args.candidate.length) {
        // Augment the native candidate with the parsed fields.
        let nativeCandidate = new NativeRTCIceCandidate(args);
        let parsedCandidate = SDPUtils.parseCandidate(args.candidate);
        let augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate);

        // Add a serializer that does not serialize the extra attributes.
        augmentedCandidate.toJSON = function toJSON() {
          return {
            candidate: augmentedCandidate.candidate,
            sdpMid: augmentedCandidate.sdpMid,
            sdpMLineIndex: augmentedCandidate.sdpMLineIndex,
            usernameFragment: augmentedCandidate.usernameFragment
          };
        };
        return augmentedCandidate;
      }
      return new NativeRTCIceCandidate(args);
    };*/
    /*
     v=0
    o=mozilla...THIS_IS_SDPARTA-70.0.1 1294083410107926052 0 IN IP4 0.0.0.0
    s=-
    t=0 0
    a=fingerprint:sha-256 74:80:23:02:8E:F5:53:D3:6B:A2:5B:75:CF:F5:56:05:52:60:AB:8D:92:58:F2:5D:48:DA:B6:FA:7F:9A:FD:CC
    a=group:BUNDLE 0
    a=ice-options:trickle
    a=msid-semantic:WMS *
    m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101
    c=IN IP4 0.0.0.0
    a=recvonly
    a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
    a=extmap:2/recvonly urn:ietf:params:rtp-hdrext:csrc-audio-level
    a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid
    a=fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1
    a=fmtp:101 0-15
    a=ice-pwd:d916c1af80af47a3327a49711809ff3e
    a=ice-ufrag:298aa4af
    a=mid:0
    a=rtcp-mux
    a=rtpmap:109 opus/48000/2
    a=rtpmap:9 G722/8000/1
    a=rtpmap:0 PCMU/8000
    a=rtpmap:8 PCMA/8000
    a=rtpmap:101 telephone-event/8000/1
    a=setup:actpass
    a=ssrc:1720545348 cname:{1b2c4bea-3b9f-430a-a3a2-085812ced250}
    */
    //接收描述信息
    function gotDescription(desc) {
      begin = window.performance.now();
      candidates = [];
      window.desc = desc;
      console.log('desc', desc);
      pc.setLocalDescription(desc).then((result) => {
        console.log('setLocalDescription result:', result)
      });
    }

    //没有描述信息,建立失败
    function noDescription(error) {
      console.log('Error creating offer: ', error);
    }

    //格式化信息
    // function formatPriority(priority) {
    //   return [
    //     priority >> 24,
    //     (priority >> 8) & 0xFFFF,
    //     priority & 0xFF
    //   ].join(' | ');
    // }

    pc.createOffer().then(
      gotDescription,
      noDescription
    );

    // pc.createOffer().then(e=>pc.setLocalDescription(e));
    pc.ondatachannel = function (ev) {
      console.log('Data channel is created!');
      window.ev = ev;
      ev.channel.onopen = function () {
        console.log('Data channel is open and ready to be used.');
        ev.channel.onmessage = function (evm) {
          console.log('Recieve a message!');
          window.evm = evm;
          console.log('Message is: ', evm.data);
        }
      };
    };

    pc.onicecandidate = (e) => console.log('onicecandidate', e);
    pc.onicegatheringstatechange = (e) => console.log('onicegatheringstatechange', e);
    pc.oniceconnectionstatechange = (e) => console.log('oniceconnectionstatechange', e);
    pc.onaddstream = (e) => console.log('onaddstream', e);
    pc.onicecandidateerror = (e) => console.log('onicecandidateerror', e);
    pc.onnegotiationneeded = (e) => console.log('onnegotiationneeded', e);
    pc.onremovestream = (e) => console.log('onremovestream', e);
    pc.onsignalingstatechange = (e) => console.log('onsignalingstatechange', e);

    let dc = pc.createDataChannel('');
    // console.log('dc', dc);
    // pc.createOffer().then(offer=>pc.setLocalDescription(offer)).then(window.sdp1=pc.localDescription);

  </script>

</body>
</html>